import { Provide } from '@midwayjs/core';
import { exec } from 'child_process';
import * as fs from 'fs';
import * as path from 'path';
/**
 * XBM生成服务
 */
@Provide()
export class XBMService {

    /**
     * 生成紧贴文字内容的XBM并返回ArrayBuffer
     * @param {string} name - 要转换的文本
     * @param {string} fontPath - 字体文件路径
     * @param {number} [pointsize=14] - 字体大小
     * @param {string|null} [xbmOutPath=null] - （调试用）XBM文件输出路径
     * @returns {Promise<ArrayBuffer>} - 包含元信息和紧贴文字的XBM数据
     */
    async textToXbm(name: string, fontPath: string, pointsize = 14, xbmOutPath: string | null = null): Promise<ArrayBuffer> {
        console.log('使用的字体路径:', fontPath);
        console.log('字体文件是否存在:', fs.existsSync(fontPath));
        // 构建ImageMagick命令
        const command = `convert -background white -fill black ` +
            `-font "${fontPath.replace(/"/g, '\\"')}" ` +
            `-pointsize ${pointsize} ` +
            `label:"${name.replace(/"/g, '\\"')}" ` +
            `-monochrome -trim +repage xbm:-`;

        // 执行命令并获取输出
        const xbmContent = await new Promise((resolve, reject) => {
            exec(command, {
                encoding: 'utf-8',
                maxBuffer: 1024 * 1024
            }, (error, stdout, stderr) => {
                console.log('命令执行结果:', { error, stdout, stderr });
                if (error) {
                    console.error('完整错误信息:', error);
                    console.error('标准错误输出:', stderr);
                    reject(new Error(`图像生成失败: ${error.message}\n${stderr}`));
                    return;
                }
                resolve(stdout);
            });
        }) as any;
        console.log('xbmContent 输出内容', xbmContent)

        // 调试：保存原始XBM文件
        if (xbmOutPath) {
            try {
                if (!fs.existsSync(xbmOutPath)) {
                    fs.mkdirSync(xbmOutPath, { recursive: true });
                }
                // 定义最终的文件路径（目录 + 文件名）
                const xbmFilePath = path.join(xbmOutPath, `${name}.xbm`);
                await fs.writeFileSync(xbmFilePath, xbmContent);
                console.log(`[调试] XBM文件已保存到: ${xbmOutPath}`);
            } catch (saveError) {
                console.error(`[调试] 无法保存XBM文件: ${saveError.message}`);
            }
        }

        // 解析XBM内容
        try {
            const widthMatch = xbmContent.match(/#define\s+\S+_width\s+(\d+)/);
            const heightMatch = xbmContent.match(/#define\s+\S+_height\s+(\d+)/);
            const hexDataMatch = xbmContent.match(
                /static\s+(?:unsigned\s+)?char\s+\S+_bits\[\]\s*=\s*{\s*([^}]+)\s*}/
            );

            if (!widthMatch || !heightMatch || !hexDataMatch) {
                console.error('原始XBM内容:', xbmContent);
                throw new Error('XBM格式解析失败');
            }

            const width = parseInt(widthMatch[1]);
            const height = parseInt(heightMatch[1]);

            // 解析十六进制数据
            const hexValues = hexDataMatch[1]
                .replace(/\s/g, '')
                .split(',')
                .filter(s => s.startsWith('0x'))
                .map(s => parseInt(s, 16));

            // 创建ArrayBuffer (4字节头 + XBM数据)
            const buffer = new ArrayBuffer(4 + hexValues.length); // 总长度 = 4字节头 + XBM数据
            const header = new Uint8Array(buffer, 0, 4); // 前4字节：头信息
            const data = new Uint8Array(buffer, 4);  // 剩余字节：XBM数据
            const x = (64 - width) / 2

            // x y width height
            header.set([x, 10, width, height]); // x: 水平偏移, y: 固定为5, width/height: 图像尺寸
            data.set(hexValues); // 填充XBM数据

            return buffer;
        } catch (parseError) {
            throw new Error(`XBM数据处理失败: ${parseError.message}`);
        }
    }



    /**
        * 生成紧贴文字内容的XBM并返回ArrayBuffer
        * @param name 姓名
        * @param maxWidth 最大宽度
        * @param {string} fontPath - 字体文件路径
        * @param {number} [pointsize=14] - 字体大小
        * @param {string|null} [xbmOutPath=null] - （调试用）XBM文件输出路径
        * @returns {Promise<ArrayBuffer>} - 包含元信息和紧贴文字的XBM数据
        */
    async generateXbmWithWidthLimit(name, maxWidth = 64, fontPath, pointsize, xbmOutPath) {
        let currentName = name;
        let buffer;
        let uint8;
        // 循环调用 textToXbm 直到 width > maxWidth
        do {
            buffer = await this.textToXbm(currentName, fontPath, pointsize, xbmOutPath);
            uint8 = new Uint8Array(buffer);
            console.log('完整头信息:', {
                x偏移: uint8[0],
                y偏移: uint8[1],
                宽度: uint8[2],
                高度: uint8[3]
            });
            // 检查buffer的第三个字节（宽度）是否超过限制
            if (uint8[2] > maxWidth) {
                // 如果超过限制，去掉最后一个字符
                currentName = currentName.slice(0, -1);
                // 如果已经没有字符可去，直接退出循环
                if (currentName.length === 0) {
                    throw new Error("无法生成满足宽度限制的XBM，即使使用空字符串");
                }
            }
        } while (uint8[2] > maxWidth);
        // 更新item.name为最终使用的名称（可选）
        name = currentName;
        console.log('refreash name', name)
        return buffer;
    }



    /**
     * 打印XBM信息（调试用）
     * @param {ArrayBuffer} arrayBuffer 
     */
    printXBMInfo(arrayBuffer: ArrayBuffer) {
        const header = new Uint8Array(arrayBuffer, 0, 4);
        const data = new Uint8Array(arrayBuffer, 4);

        console.log('=== XBM信息 ===');
        console.log(`尺寸: ${header[2]}x${header[3]} 像素`);
        console.log(`数据字节数: ${data.length}`);
        console.log('前10字节数据:', Array.from(data.slice(0, 10)).map(b => '0x' + b.toString(16).padStart(2, '0')).join(', '));
    }

    /**
     * XBM可视化（调试用）
     * @param {ArrayBuffer} arrayBuffer 
     */
    visualizeXBM(arrayBuffer: ArrayBuffer) {
        const header = new Uint8Array(arrayBuffer, 0, 4);
        const data = new Uint8Array(arrayBuffer, 4);
        const width = header[2];
        const height = header[3];
        const bytesPerRow = Math.ceil(width / 8);

        console.log(`XBM可视化 ${width}x${height}:`);
        for (let y = 0; y < height; y++) {
            let row = '';
            for (let xByte = 0; xByte < bytesPerRow; xByte++) {
                const byte = data[y * bytesPerRow + xByte];
                for (let bit = 7; bit >= 0; bit--) {
                    const pixel = (byte >> bit) & 1;
                    row += pixel ? '■' : '□';
                    if (row.length >= width) break;
                }
            }
            console.log(row.substring(0, width));
        }
    }
}
